package org.zxyj.manage.service.impl;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zxyj.manage.entity.CourseTemplateArea;
import org.zxyj.manage.service.ICropService;
import org.zxyj.manage.service.IPointRecognitionService;

/**
 * 像素点识别实现类
 * @author     ly
 * @see        [相关类/方法]
 * @since      [产品/模块版本]
 */
@Service
public class PointRecognitionServiceImpl implements IPointRecognitionService{
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private ICropService cropService;
	
    private Map<Integer,String> daxxMap = new HashMap<Integer,String>();
    public PointRecognitionServiceImpl(){
        daxxMap.put(0, "A");
        daxxMap.put(1, "B");
        daxxMap.put(2, "C");
        daxxMap.put(3, "D");
        daxxMap.put(4, "E");
        daxxMap.put(5, "F");
    }
    
    /**
     * 识别考生编号
     * @param image 图片流
     * @param area_width 区域宽度
     * @param area_height 区域高度
     * @param kh_start_x X轴偏移量
     * @param kh_start_y Y轴偏移量
     * @param singleWidth 单个小块区域宽度
     * @param singleHeight 单个区域小块高度
     * @param rows 行数
     * @param cols 列数
     * @return
     * @throws IOException
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    /*public Map<String, String> recognitionKsbh(BufferedImage image,
        int area_width, int area_height, int kh_start_x, int kh_start_y,
        int singleWidth, int singleHeight, int rows, int cols) throws IOException*/
    public Map<String, String> recognitionKsbh(Map<String,Object> params) throws IOException
    {
        Map<String, String> result = new HashMap<String, String>();
        BufferedImage image = (BufferedImage) params.get("image");
        Integer width = Integer.valueOf(params.get("width")+"");
        Integer height = Integer.valueOf(params.get("height")+"");
        Integer start_x = Integer.valueOf(params.get("start_x")+"");
        Integer start_y = Integer.valueOf(params.get("start_y")+"");
        Integer singleWidth = Integer.valueOf(params.get("singleWidth")+"");
        Integer singleHeight = Integer.valueOf(params.get("singleHeight")+"");
        Integer row_count = Integer.valueOf(params.get("row_count")+"");
        Integer col_count = Integer.valueOf(params.get("col_count")+"");
        
        int blank_x = (width - (col_count * singleWidth)) / (col_count - 1);// 列间隔宽度
        int blank_y = (height - (row_count * singleHeight)) / (row_count - 1);// 行间隔高度
        int imgW = image.getWidth();
        int imgH = image.getHeight();
        boolean flag = false;
        
        // kh_start_x 对考号起始点宽度进行正负6PX偏差校对，以增加识别准确率
        for (int i = 6; i > -7; i--)
        {
            int start_x1 = start_x + i;
            if (flag) break;
            
            // 将列间距blank_x 正负偏差3PX校对
            /*
             * for(int a=2;a>-3;a--){ if(flag)break; int blank_x1 = blank_x + a;
             */
            int w = start_x1 + (col_count * singleWidth) + (col_count - 1) * blank_x;
            if (w > imgW) continue;
            if (start_x1 >= 0)
            {
                // kh_start_y 对考号起始点高度进行正负6PX偏差校对，以增加识别准确率
                for (int j = 6; j > -7; j--)
                {
                    int kh_start_y1 = start_y + j;
                    if (kh_start_y1 >= 0)
                    {
                        // 将列间距blank_y 正负偏差3PX校对
                        for (int b = 2; b > -3; b--)
                        {
                            if (flag) break;
                            int blank_y1 = blank_y + b;
                            int h = kh_start_y1 + (row_count * singleHeight) + (row_count - 1) * blank_y1;
                            if (h > imgH) continue;
                            result = getKsbh(image, width, height, start_x1, kh_start_y1, singleWidth, singleHeight,
                            		row_count, col_count, blank_x, blank_y1);
                            // System.out.println("blank_y="+blank_y+"##########i="+i+",j="+j+",blank_x1="+blank_x+",blank_y1="+blank_y1+",kh_start_x1="+kh_start_x1+",kh_start_y1="+kh_start_y1+",ksbh="+param.get("result")+",b="+b);
                            if (result.get("flag").equals("1"))
                            {
                                flag = true;
                                break;
                            }
                        }
                    }
                }
            }
            // }
        }
        
        return result;
    }
    
    /**
     * 识别获取考生编号
     * @param image 图片流
     * @param area_width 区域宽度
     * @param area_height 区域高度
     * @param kh_start_x X轴偏移量
     * @param kh_start_y Y轴偏移量
     * @param singleWidth 单个小块区域宽度
     * @param singleHeight 单个小块区域高度
     * @param rows 行数
     * @param cols 列数
     * @param blank_x 列间距
     * @param blank_y 行间距
     * @return
     * @throws IOException
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, String> getKsbh(BufferedImage image,
        int area_width, int area_height, int kh_start_x, int kh_start_y,
        int singleWidth, int singleHeight, int rows, int cols, int blank_x,
        int blank_y) throws IOException
    {
        Map<String, String> param = new HashMap<String, String>();
        // 计算行间距和列间距
        // int blank_x = (area_width - (cols * singleWidth)) / (cols -1);//列间隔宽度
        // int blank_y = (area_height - (rows * singleHeight)) / (rows -1);//行间隔高度
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("start_x", kh_start_x);
        map.put("start_y", kh_start_y);
        map.put("blank_x", blank_x);
        map.put("blank_y", blank_y);
        map.put("rows", rows);
        map.put("cols", cols);
        map.put("box_x", singleWidth);
        map.put("box_y", singleHeight);
        String[] ksbh_ = judge_all(map, image);// 获取考生编号
        image = null;
        String ksbh = "";
        for (int k = 0; k < ksbh_.length; k++)
        {
            if (ksbh_[k] == null)
            {
                ksbh += "*";
            }
            else
            {
                ksbh += ksbh_[k];
            }
        }
        
        boolean flag = ksbh.contains("*");// 判断考生编号是否包含*，如含有则说明内容未识别出来
        if (flag)
        {
            param.put("flag", "0");
            param.put("result", ksbh);
        }
        else
        {
            param.put("flag", "1");
            param.put("result", ksbh);
        }
        return param;
    }
    
    /**
     * 识别缺考区域
     * @param image 图片流
     * @param singleWidth 单个小块宽度
     * @param singleHeight 单个小块高度
     * @param rows 行数
     * @param cols 列数
     * @param blank_x 列间距
     * @param blank_y 行间距
     * @return
     * @throws IOException
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public boolean recognitionQk(BufferedImage image, int singleWidth,
        int singleHeight, int rows, int cols, int blank_x, int blank_y) throws IOException
    {
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("start_x", blank_x);
        map.put("start_y", blank_y);
        map.put("blank_x", 0);
        map.put("blank_y", 0);
        map.put("rows", rows);
        map.put("cols", cols);
        map.put("box_x", singleWidth);
        map.put("box_y", singleHeight);
        String[] str = judge_all(map, image);// 获取识别数据
        image=null;
        boolean flag = false;
        if (str.length > 0) {
            if (str[0] == null) {
                flag = false;// 未识别出填涂
            } else {
                flag = true;// 填涂
            }
        }
        return flag;
    }
    
    /**
     * 灰度化处理
     * @param bi 图片流
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public int[][] graying(BufferedImage bi)
    {
        // 高度和宽度
        int width = bi.getWidth();
        int height = bi.getHeight();
        int[][] gray = new int[width][height];
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                Color c = new Color(bi.getRGB(x, y));
                // 灰阶值: Y = 0.299 * R + 0.587 * G + 0.114 * B 取蓝色作为RGB最大值
                // gray[x][y] = c.getBlue();//(int)(c.getRed() * 0.299 + c.getGreen() * 0.587 + c.getBlue() * 0.114);
                gray[x][y] =
                    (int)(c.getRed() * 0.299 + c.getGreen() * 0.587 + c.getBlue() * 0.114);
            }
        }
        return gray;
    }
    
    /**
     * 计算区域块有效宽度和高度
     * @param image 图片流
     * @param type 0:小区域面积 1：大区域面积
     * @return
     * @throws IOException
     * @see [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, Object> getAreaResult(BufferedImage image,int type) throws IOException
    {
        Map<String, Object> map = new HashMap<String, Object>();
        // 图片灰度处理得到像素RGB值
        int[][] gray = graying(image);
        
        if (type == 0)
        {// 小图
            map.putAll(getSmallAreaHeight(gray));
            map.putAll(getAreaWidth(gray));
        }
        else if (type == 1)
        {// 大图
            map.putAll(getBigAreaHeight(gray));
            map.putAll(getBigAreaWidth(gray));
        }
        else if (type == 2)
        {// 特征点图-左侧
            map.putAll(getTzdAreaWidthHeight(gray));
        }
        else if (type == 3)
        {// 特征点图-右侧
            map.putAll(getTzdAreaRightWidthHeight(gray));
        }
        
        return map;
    }
    
    /**
     * 求Map<K,V>中Value(值)最大值出现次数最多的所对应的key值
     * @param map
     * @return
     */
    public Integer getMaxValue(Map<Integer, Integer> map)
    {
        if (map == null)
            return null;
        Integer max_key = 0;
        Integer max_value = 0;
        for (Entry<Integer, Integer> entry : map.entrySet())
        {
            Integer value = entry.getValue();
            if (value > max_value)
            {
                max_key = entry.getKey();
                max_value = value;
            }
        }
        return max_key;
    }
    
    /**
     * 求Map<K,V>中key的最大值出现次数
     * @param map
     * @return
     */
    public Integer getMaxHeightValue(Map<Integer, Integer> map)
    {
        if (map == null)
            return null;
        Integer max_key = 0;
        // 将map按key值大小排序，降序排列
        List<Map.Entry<Integer, Integer>> list =
            new ArrayList<Map.Entry<Integer, Integer>>(map.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>()
        {
            // 升序排序
            public int compare(Entry<Integer, Integer> o1,
                Entry<Integer, Integer> o2)
            {
                return o2.getKey().compareTo(o1.getKey());
            }
        });
        
        for (Map.Entry<Integer, Integer> mapping : list)
        {
            if (mapping.getValue() < 3)
            {
                continue;
            }
            else
            {
                max_key = mapping.getKey();
                break;
            }
        }
        
        return max_key;
    }
    
    /**
     * 计算区域高度 --用于计算小面积区域块
     * @param gray 二值化数组
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, Integer> getSmallAreaHeight(int[][] gray)
    {
        Map<String, Integer> map = new HashMap<String, Integer>();
        // 循环判断所有像素点
        int y1 = 0;// 每列黑色点起始坐标点
        int y2 = 0;// 每列黑色点结束坐标点
        int areaHeight = 0;// 填涂区域块高度
        
        // 得到填涂区域高度
        List<Integer> pointList = new ArrayList<Integer>();
        List<Integer> pointList1 = new ArrayList<Integer>();
        Map<Integer, Integer> startPiontY_Map = new HashMap<Integer, Integer>();// 存放每行起始像素Y坐标点
        Map<Integer, Integer> endPiontY_Map = new HashMap<Integer, Integer>();// 存放每行结束像素Y坐标点
     // 得到填涂区域高度
        int width= gray.length;
        int height = gray[0].length;
        for (int i = 0; i < width; i++)
        {// 像素点行
            int count_y = 0;// 黑点总数
            int areaHeight_ = 0;
            for (int j = 0; j < height; j++)
            {// 像素点列
             // 判断黑点，如果是黑点则记录该点坐标
                if (gray[i][j] <= 100)
                {
                    if (count_y == 0)
                    {// 存放起始点坐标值
                        y1 = j;
                        //System.out.println("i="+i+",j="+j);
                    }else {
                        y2 = j + 1;
                    }
                    int y3 = y2 - y1;// 高度
                    if (y3 > areaHeight_)
                    {
                    	areaHeight_ = y3;
                    }
                    count_y++;
                }
            }
            
            pointList.add(areaHeight_);
            startPiontY_Map.put(areaHeight_, y1);
            endPiontY_Map.put(areaHeight_, y2);
        }
        
        // 计算宽度稳定值，取宽度值数量最多的值作为最终宽度值，减少宽度误差范围
        Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
        for (Integer x : pointList)
        {
            // 去除值为0的值
            if (x > 0)
            {
                pointList1.add(x);
            }
        }
        
        for (Integer x : pointList1)
        {
            if (countMap.isEmpty())
            {
                countMap.put(x, 1);
            }
            else
            {
                if (countMap.get(x) == null)
                {
                    countMap.put(x, 1);
                }
                else
                {
                    countMap.put(x, countMap.get(x) + 1);
                }
            }
        }
        areaHeight = getMaxValue(countMap);
        map.put("height", areaHeight);
        map.put("start_y", startPiontY_Map.get(areaHeight));
        //map.put("start_y", y1);
        return map;
    }
    
    /**
     * 计算区域高度 --用于计算考号大面积区域块
     * @param gray 二值化数组
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, Integer> getBigAreaHeight(int[][] gray)
    {
        Map<String, Integer> map = new HashMap<String, Integer>();
        int areaHeight = 0;// 填涂区域块高度
        
        // 得到填涂区域高度
        List<Integer> pointList = new ArrayList<Integer>();
        List<Integer> pointList1 = new ArrayList<Integer>();
        Map<Integer, Integer> startPiontY_Map = new HashMap<Integer, Integer>();// 存放每列起始像素Y坐标点
        Map<Integer, Integer> endPiontY_Map = new HashMap<Integer, Integer>();// 存放每列结束像素Y坐标点
        // System.out.println("gray.length="+gray.length);
        // 循环判断所有像素点
        for (int i = 0; i < gray.length; i++)
        {// 像素点行
            int y1 = 0;// 每行黑色点起始坐标点
            int y2 = 0;// 每行黑色点结束坐标点
            int count_y = 0;// 黑点总数
            int areaHeight_ = 0;
            /*
             * for (int j = 0; j < gray[i].length; j++){//像素点列 //判断黑点，如果是黑点则记录该点坐标 if (gray[i][j] <= 100){
             * if(count_y==0){//存放起始点坐标值 y1 = j+1; }else{ y2 = j+1; } int y3 = y2 - y1;//高度 if(y3 > areaHeight_){
             * areaHeight_ = y3; } count_y++; //System.out.println("count_y="+count_y+",areaHeight="+areaHeight); } }
             */
            
            // System.out.println("gray[i].length="+gray[i].length);
            for (int j = 0; j < gray[i].length; j++)
            {// 像素点列
                if (gray[i][j] <= 100)
                {
                    // 排除横线干扰，取横向连续的60个点判断是否连接
                    if (i < gray.length - 60)
                    {
                        if (gray[i + 1][j] <= 100 && gray[i + 2][j] <= 100
                            && gray[i + 3][j] <= 100 && gray[i + 4][j] <= 100
                            && gray[i + 5][j] <= 100 && gray[i + 6][j] <= 100
                            && gray[i + 7][j] <= 100 && gray[i + 8][j] <= 100
                            && gray[i + 9][j] <= 100 && gray[i + 10][j] <= 100
                            && gray[i + 11][j] <= 100 && gray[i + 12][j] <= 100
                            && gray[i + 13][j] <= 100 && gray[i + 14][j] <= 100
                            && gray[i + 15][j] <= 100 && gray[i + 16][j] <= 100
                            && gray[i + 17][j] <= 100 && gray[i + 18][j] <= 100
                            && gray[i + 19][j] <= 100 && gray[i + 20][j] <= 100
                            && gray[i + 21][j] <= 100 && gray[i + 22][j] <= 100
                            && gray[i + 23][j] <= 100 && gray[i + 24][j] <= 100
                            && gray[i + 25][j] <= 100 && gray[i + 26][j] <= 100
                            && gray[i + 27][j] <= 100 && gray[i + 28][j] <= 100
                            && gray[i + 29][j] <= 100 && gray[i + 30][j] <= 100
                            && gray[i + 31][j] <= 100 && gray[i + 32][j] <= 100
                            && gray[i + 33][j] <= 100 && gray[i + 34][j] <= 100
                            && gray[i + 35][j] <= 100 && gray[i + 36][j] <= 100
                            && gray[i + 37][j] <= 100 && gray[i + 38][j] <= 100
                            && gray[i + 39][j] <= 100 && gray[i + 40][j] <= 100
                            && gray[i + 41][j] <= 100 && gray[i + 42][j] <= 100
                            && gray[i + 43][j] <= 100 && gray[i + 44][j] <= 100
                            && gray[i + 45][j] <= 100 && gray[i + 46][j] <= 100
                            && gray[i + 47][j] <= 100 && gray[i + 48][j] <= 100
                            && gray[i + 49][j] <= 100 && gray[i + 50][j] <= 100
                            && gray[i + 51][j] <= 100 && gray[i + 52][j] <= 100
                            && gray[i + 53][j] <= 100 && gray[i + 54][j] <= 100
                            && gray[i + 55][j] <= 100 && gray[i + 56][j] <= 100
                            && gray[i + 57][j] <= 100 && gray[i + 58][j] <= 100
                            && gray[i + 59][j] <= 100 && gray[i + 60][j] <= 100)
                        {
                            break;
                        }
                    }
                    
                    // 去除竖线情况下起始连续点在30个之内的列，排除竖线干扰
                    if (j < 31)
                    {
                        if (gray[i][j + 1] <= 100 && gray[i][j + 2] <= 100
                            && gray[i][j + 3] <= 100 && gray[i][j + 4] <= 100
                            && gray[i][j + 5] <= 100 && gray[i][j + 6] <= 100
                            && gray[i][j + 7] <= 100 && gray[i][j + 8] <= 100
                            && gray[i][j + 9] <= 100 && gray[i][j + 10] <= 100
                            && gray[i][j + 11] <= 100 && gray[i][j + 12] <= 100
                            && gray[i][j + 13] <= 100 && gray[i][j + 14] <= 100
                            && gray[i][j + 15] <= 100 && gray[i][j + 16] <= 100
                            && gray[i][j + 17] <= 100 && gray[i][j + 18] <= 100
                            && gray[i][j + 19] <= 100 && gray[i][j + 20] <= 100
                            && gray[i][j + 21] <= 100 && gray[i][j + 22] <= 100
                            && gray[i][j + 23] <= 100 && gray[i][j + 24] <= 100
                            && gray[i][j + 25] <= 100 && gray[i][j + 26] <= 100
                            && gray[i][j + 27] <= 100 && gray[i][j + 28] <= 100
                            && gray[i][j + 29] <= 100 && gray[i][j + 30] <= 100)
                        {
                            break;
                        }
                    }
                    
                    if (count_y == 0)
                    {// 存放起始点坐标值
                        if (j > 40)
                        {
                            break;
                        }
                        y1 = j;
                    }
                    else
                    {
                        y2 = j + 1;
                    }
                    int y3 = y2 - y1;// 高度
                    if (y3 > areaHeight_)
                    {
                        areaHeight_ = y3;
                    }
                    count_y++;
                }
            }
            pointList.add(areaHeight_);
            startPiontY_Map.put(areaHeight_, y1);
            endPiontY_Map.put(areaHeight_, y2);
        }
        
        // 计算高度稳定值，取高度值数量最多的值作为最终宽度值，减少高度误差范围
        Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
        for (Integer x : pointList)
        {
            // 去除值为0的值
            if (x > 0)
            {
                pointList1.add(x);
            }
        }
        
        for (Integer x : pointList1)
        {
            if (countMap.isEmpty())
            {
                countMap.put(x, 1);
            }
            else
            {
                if (countMap.get(x) == null)
                {
                    countMap.put(x, 1);
                }
                else
                {
                    countMap.put(x, countMap.get(x) + 1);
                }
            }
        }
        
        areaHeight = getMaxValue(countMap);
        map.put("height", areaHeight);
        map.put("start_y", startPiontY_Map.get(areaHeight));
        map.put("end_y", endPiontY_Map.get(areaHeight));
        // System.out.println("~~~~~~~~~~~~~~~~~~~~~~~areaHeight_="+areaHeight+",start_y="+startPiontY_Map.get(areaHeight)+",end_y="+endPiontY_Map.get(areaHeight));
        return map;
    }
    
    /**
     * 计算区域宽度 --用于计算考号大面积区域块
     * @param gray 二值化数组
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, Integer> getBigAreaWidth(int[][] gray)
    {
        Map<String, Integer> map = new HashMap<String, Integer>();
        int areaWidth = 0;// 填涂区域块宽度
        
        // 得到填涂区域宽度
        List<Integer> pointList = new ArrayList<Integer>();
        List<Integer> pointList1 = new ArrayList<Integer>();
        Map<Integer, Integer> startPiontX_Map = new HashMap<Integer, Integer>();// 存放每行起始像素X坐标点
        Map<Integer, Integer> endPiontX_Map = new HashMap<Integer, Integer>();// 存放每行结束像素X坐标点
        // 循环判断所有像素点
        for (int i = 0; i < gray[0].length; i++)
        {// 像素点行高
            int x1 = 0;// 每行黑色点起始坐标点
            int x2 = 0;// 每行黑色点结束坐标点
            int count_x = 0;
            int areaWidth_ = 0;
            for (int j = 0; j < gray.length; j++)
            {// 像素点列宽
             // 判断黑点，如果是黑点则记录该点坐标
                if (gray[j][i] <= 100)
                {
                    // System.out.println("gray["+j+"]["+i+"]="+gray[j][i]);
                    // System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$i="+i+",j="+j);
                    // 排除横线干扰，取横向连续的60个点判断是否连接
                    if (j < gray.length - 60)
                    {
                        if (gray[j + 1][i] <= 100 && gray[j + 2][i] <= 100
                            && gray[j + 3][i] <= 100 && gray[j + 4][i] <= 100
                            && gray[j + 5][i] <= 100 && gray[j + 6][i] <= 100
                            && gray[j + 7][i] <= 100 && gray[j + 8][i] <= 100
                            && gray[j + 9][i] <= 100 && gray[j + 10][i] <= 100
                            && gray[j + 11][i] <= 100 && gray[j + 12][i] <= 100
                            && gray[j + 13][i] <= 100 && gray[j + 14][i] <= 100
                            && gray[j + 15][i] <= 100 && gray[j + 16][i] <= 100
                            && gray[j + 17][i] <= 100 && gray[j + 18][i] <= 100
                            && gray[j + 19][i] <= 100 && gray[j + 20][i] <= 100
                            && gray[j + 21][i] <= 100 && gray[j + 22][i] <= 100
                            && gray[j + 23][i] <= 100 && gray[j + 24][i] <= 100
                            && gray[j + 25][i] <= 100 && gray[j + 26][i] <= 100
                            && gray[j + 27][i] <= 100 && gray[j + 28][i] <= 100
                            && gray[j + 29][i] <= 100 && gray[j + 30][i] <= 100
                            && gray[j + 31][i] <= 100 && gray[j + 32][i] <= 100
                            && gray[j + 33][i] <= 100 && gray[j + 34][i] <= 100
                            && gray[j + 35][i] <= 100 && gray[j + 36][i] <= 100
                            && gray[j + 37][i] <= 100 && gray[j + 38][i] <= 100
                            && gray[j + 39][i] <= 100 && gray[j + 40][i] <= 100
                            && gray[j + 41][i] <= 100 && gray[j + 42][i] <= 100
                            && gray[j + 43][i] <= 100 && gray[j + 44][i] <= 100
                            && gray[j + 45][i] <= 100 && gray[j + 46][i] <= 100
                            && gray[j + 47][i] <= 100 && gray[j + 48][i] <= 100
                            && gray[j + 49][i] <= 100 && gray[j + 50][i] <= 100
                            && gray[j + 51][i] <= 100 && gray[j + 52][i] <= 100
                            && gray[j + 53][i] <= 100 && gray[j + 54][i] <= 100
                            && gray[j + 55][i] <= 100 && gray[j + 56][i] <= 100
                            && gray[j + 57][i] <= 100 && gray[j + 58][i] <= 100
                            && gray[j + 59][i] <= 100 && gray[j + 60][i] <= 100)
                        {
                            break;
                        }
                    }
                    
                    // 去除竖线情况下起始连续点在50个之内的列，排除竖线干扰
                    if (i < gray[0].length - 30)
                    {
                        if (gray[j][i + 1] <= 100 && gray[j][i + 2] <= 100
                            && gray[j][i + 3] <= 100 && gray[j][i + 4] <= 100
                            && gray[j][i + 5] <= 100 && gray[j][i + 6] <= 100
                            && gray[j][i + 7] <= 100 && gray[j][i + 8] <= 100
                            && gray[j][i + 9] <= 100 && gray[j][i + 10] <= 100
                            && gray[j][i + 11] <= 100 && gray[j][i + 12] <= 100
                            && gray[j][i + 13] <= 100 && gray[j][i + 14] <= 100
                            && gray[j][i + 15] <= 100 && gray[j][i + 16] <= 100
                            && gray[j][i + 17] <= 100 && gray[j][i + 18] <= 100
                            && gray[j][i + 19] <= 100 && gray[j][i + 20] <= 100
                            && gray[j][i + 21] <= 100 && gray[j][i + 22] <= 100
                            && gray[j][i + 23] <= 100 && gray[j][i + 24] <= 100
                            && gray[j][i + 25] <= 100 && gray[j][i + 26] <= 100
                            && gray[j][i + 27] <= 100 && gray[j][i + 28] <= 100
                            && gray[j][i + 29] <= 100 && gray[j][i + 30] <= 100)
                        {
                            continue;
                        }
                    }
                    
                    if (count_x == 0)
                    {// 存放起始点坐标值
                        if (j > 40)
                        {
                            break;
                        }
                        x1 = j + 1;
                    }
                    else
                    {
                        x2 = j + 1;
                    }
                    
                    int x3 = x2 - x1;// 宽度
                    if (x3 > areaWidth_)
                    {
                        areaWidth_ = x3;
                    }
                    count_x++;
                }
                // System.out.println("ij" + i + ">>>>>>j" + j);
            }
            pointList.add(areaWidth_);
            startPiontX_Map.put(areaWidth_, x1);
            endPiontX_Map.put(areaWidth_, x2);
            // System.out.println("x2="+x2+",x1="+x1+",areaWidth_="+areaWidth_);
        }
        
        // 计算宽度稳定值，取宽度值数量最多的值作为最终宽度值，减少宽度误差范围
        Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
        for (Integer x : pointList)
        {
            // 去除值为0的值
            if (x > 0)
            {
                pointList1.add(x);
            }
        }
        
        for (Integer x : pointList1)
        {
            if (countMap.isEmpty())
            {
                countMap.put(x, 1);
            }
            else
            {
                if (countMap.get(x) == null)
                {
                    countMap.put(x, 1);
                }
                else
                {
                    countMap.put(x, countMap.get(x) + 1);
                }
            }
        }
        areaWidth = getMaxValue(countMap);
        map.put("width", areaWidth + 1);
        map.put("start_x", startPiontX_Map.get(areaWidth));
        map.put("end_x", endPiontX_Map.get(areaWidth));
        // System.out.println("~~~~~~~~~~~~~~~~~~~~~~~areaWidth="+areaWidth+",start_x="+startPiontX_Map.get(areaWidth)+",end_x="+endPiontX_Map.get(areaWidth));
        return map;
    }
    
    /**
     * 计算区域宽度
     * @param gray 二值化数组
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, Integer> getAreaWidth(int[][] gray)
    {
        Map<String, Integer> map = new HashMap<String, Integer>();
        // 循环判断所有像素点
        int x1 = 0;// 每行黑色点起始坐标点
        int x2 = 0;// 每行黑色点结束坐标点
        int areaWidth = 0;// 填涂区域块宽度
        
        // 得到填涂区域宽度
        List<Integer> pointList = new ArrayList<Integer>();
        List<Integer> pointList1 = new ArrayList<Integer>();
        Map<Integer, Integer> startPiontX_Map = new HashMap<Integer, Integer>();// 存放每行起始像素X坐标点
        Map<Integer, Integer> endPiontX_Map = new HashMap<Integer, Integer>();// 存放每行结束像素X坐标点
        for (int i = 0; i < gray[0].length; i++)
        {// 像素点行
            int count_x = 0;
            int areaWidth_ = 0;
            for (int j = 0; j < gray.length; j++)
            {// 像素点列
             // 判断黑点，如果是黑点则记录该点坐标
                if (gray[j][i] <= 100)
                {
                    if (count_x == 0)
                    {// 存放起始点坐标值
                        x1 = j;
                    }
                    else
                    {
                        x2 = j + 1;
                    }
                    
                    int x3 = x2 - x1;// 宽度
                    if (x3 > areaWidth_)
                    {
                        areaWidth_ = x3;
                    }
                    count_x++;
                    // System.out.println("count_x="+count_x+",areaWidth_="+areaWidth_);
                }
            }
            pointList.add(areaWidth_);
            startPiontX_Map.put(areaWidth_, x1);
            endPiontX_Map.put(areaWidth_, x2);
        }
        
        // 计算宽度稳定值，取宽度值数量最多的值作为最终宽度值，减少宽度误差范围
        Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
        for (Integer x : pointList)
        {
            // 去除值为0的值
            if (x > 0)
            {
                pointList1.add(x);
            }
        }
        
        for (Integer x : pointList1)
        {
            if (countMap.isEmpty())
            {
                countMap.put(x, 1);
            }
            else
            {
                if (countMap.get(x) == null)
                {
                    countMap.put(x, 1);
                }
                else
                {
                    countMap.put(x, countMap.get(x) + 1);
                }
            }
        }
        areaWidth = getMaxValue(countMap);
        map.put("width", areaWidth);
        map.put("start_x", startPiontX_Map.get(areaWidth));
        map.put("end_x", endPiontX_Map.get(areaWidth));
        return map;
    }
    
    /**
     * 判断特征点起始坐标
     * @param gray 二值化数组
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, Integer> getTzdAreaWidthHeight(int[][] gray)
    {
        Map<String, Integer> map = new HashMap<String, Integer>();
        // 循环判断所有像素点
        int x = 0;// 起始坐标点X
        int y = 0;// 起始坐标点Y
        // 判断黑点，如果是黑点则记录该点坐标
        boolean flag_x = false;
        boolean flag_y = false;
        
        int width = gray.length;
        int height = gray[0].length;
        for (int i = 0; i < width - 9; i++)
        {// 像素点列
            if (flag_x)break;
            for (int j = 0; j < height - 9; j++)
            {// 像素点行
                if (gray[i][j] <= 100)
                {
                    if (gray[i + 1][j + 1] <= 100 
                        && gray[i + 2][j + 2] <= 100
                        && gray[i + 3][j + 3] <= 100
                        && gray[i + 4][j + 4] <= 100
                        && gray[i + 5][j + 5] <= 100
                        && gray[i + 6][j + 6] <= 100
                        && gray[i + 7][j + 7] <= 100
                        && gray[i + 8][j + 8] <= 100
                        && gray[i + 9][j + 9] <= 100)
                    {
                        // 存放起始点坐标值
                        x = (i + 2);
                        flag_x = true;
                        break;
                    }
                    /*
                     * if(gray[i][j+1] <= 100 && gray[i][j+2] <= 100 && gray[i][j+3] <= 100 && gray[i][j+4] <= 100 &&
                     * gray[i][j+5]<= 100 && gray[i][j+6] <= 100 && gray[i][j+7] <= 100 && gray[i][j+8] <= 100 &&
                     * gray[i][j+9] <= 100 && gray[i+1][j] <= 100 && gray[i+2][j] <= 100 && gray[i+3][j] <= 100 &&
                     * gray[i+4][j] <= 100 && gray[i+5][j]<= 100 && gray[i+6][j] <= 100 && gray[i+7][j] <= 100 &&
                     * gray[i+8][j] <= 100 && gray[i+9][j] <= 100 && gray[i+1][j+1] <= 100 && gray[i+2][j+2] <= 100 &&
                     * gray[i+3][j+3] <= 100 && gray[i+4][j+4] <= 100 && gray[i+5][j+5]<= 100){ //存放起始点坐标值 x = i+2; y =
                     * j+2; //System.out.println("x="+x+",y="+y); flag = true; break; }
                     */
                }
            }
        }
        
        for (int j1 = 0; j1 < height - 9; j1++)
        {// 像素点列
            if (flag_y)break;
            for (int i1 = 0; i1 < width - 9; i1++)
            {// 像素点行
                if (gray[i1][j1] <= 100)
                {
                    if (gray[i1 + 1][j1 + 1] <= 100
                        && gray[i1 + 2][j1 + 2] <= 100
                        && gray[i1 + 3][j1 + 3] <= 100
                        && gray[i1 + 4][j1 + 4] <= 100
                        && gray[i1 + 5][j1 + 5] <= 100
                        && gray[i1 + 6][j1 + 6] <= 100
                        && gray[i1 + 7][j1 + 7] <= 100
                        && gray[i1 + 8][j1 + 8] <= 100
                        && gray[i1 + 9][j1 + 9] <= 100)
                    {
                        // 存放起始点坐标值
                        y = (j1 + 2);
                        //System.out.println("i=" + i1 + ",j=" + j1);
                        flag_y = true;
                        break;
                    }
                }
            }
        }
        
        map.put("start_x", x);
        map.put("start_y", y);
        return map;
    }
    
    /**
     * 判断特征点起始坐标-右上角
     * @param gray 二值化数组
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String, Integer> getTzdAreaRightWidthHeight(int[][] gray)
    {
        Map<String, Integer> map = new HashMap<String, Integer>();
        // 循环判断所有像素点
        int x = 0;// 起始坐标点X
        int y = 0;// 起始坐标点Y
        // 判断黑点，如果是黑点则记录该点坐标
        boolean flag_x = false;
        boolean flag_y = false;
        int w = gray.length;
        int h = gray[0].length;
        for (int i = w - 1; i > 9; i--)
        {// 像素点行
            if (flag_x)
                break;
            for (int j = 0; j < h - 9; j++)
            {// 像素点列
                if (gray[i][j] <= 100)
                {
                    if (gray[i - 1][j + 1] <= 100 && gray[i - 2][j + 2] <= 100
                        && gray[i - 3][j + 3] <= 100
                        && gray[i - 4][j + 4] <= 100
                        && gray[i - 5][j + 5] <= 100
                        && gray[i - 6][j + 6] <= 100
                        && gray[i - 7][j + 7] <= 100
                        && gray[i - 8][j + 8] <= 100
                        && gray[i - 9][j + 9] <= 100)
                    {
                        // 存放起始点坐标值
                        x = (w - i - 1);
                        flag_x = true;
                        break;
                    }
                }
                /*
                 * if (gray[i][j] <= 100){ if(gray[i][j+1] <= 100 && gray[i][j+2] <= 100 && gray[i][j+3] <= 100 &&
                 * gray[i][j+4] <= 100 && gray[i][j+5]<= 100 && gray[i][j+6] <= 100 && gray[i][j+7] <= 100 &&
                 * gray[i][j+8] <= 100 && gray[i][j+9] <= 100 && gray[i-1][j] <= 100 && gray[i-2][j] <= 100 &&
                 * gray[i-3][j] <= 100 && gray[i-4][j] <= 100 && gray[i-5][j]<= 100 && gray[i-6][j] <= 100 &&
                 * gray[i-7][j] <= 100 && gray[i-8][j] <= 100 && gray[i-9][j] <= 100 && gray[i-1][j+1] <= 100 &&
                 * gray[i-2][j+2] <= 100 && gray[i-3][j+3] <= 100 && gray[i-4][j+4] <= 100 && gray[i-5][j+5]<= 100){
                 * //存放起始点坐标值 x = w-i; y = j; //System.out.println("x="+x+",y="+y); flag = true; break; } }
                 */}
        }
        
        for (int i = h - 1; i > 9; i--)
        {// 像素点行
            if (flag_y)
                break;
            for (int j = 0; j < w - 9; j++)
            {// 像素点列
                if (gray[i][j] <= 100)
                {
                    if (gray[i - 1][j + 1] <= 100 && gray[i - 2][j + 2] <= 100
                        && gray[i - 3][j + 3] <= 100
                        && gray[i - 4][j + 4] <= 100
                        && gray[i - 5][j + 5] <= 100
                        && gray[i - 6][j + 6] <= 100
                        && gray[i - 7][j + 7] <= 100
                        && gray[i - 8][j + 8] <= 100
                        && gray[i - 9][j + 9] <= 100)
                    {
                        // 存放起始点坐标值
                        y = j;
                        flag_y = true;
                        break;
                    }
                }
            }
        }
        
        map.put("start_x", x);
        map.put("start_y", y);
        return map;
    }
    
    /**
     * 判断所有的，入口参数分别是起始横坐标，起始纵坐标，行数，列数
     * @param map 参数
     * @param image 图片流
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public String[] judge_all(Map<String, Integer> map, BufferedImage image)
    {
        int i, j;
        int cols = map.get("cols");
        int rows = map.get("rows");
        int start_x = map.get("start_x");
        int start_y = map.get("start_y");
        int box_x = map.get("box_x");
        int box_y = map.get("box_y");
        int blank_x = map.get("blank_x");
        int blank_y = map.get("blank_y");
       // log.info(cols+"=="+rows+"=="+start_x+"=="+start_y+"=="+box_x+"=="+box_y+"=="+blank_x+"=="+blank_y);
        String[] result = new String[cols];
        for (i = 0; i < rows; i++)
        {
            for (j = 0; j < cols; j++)
            {
                if (judge_box(start_x + j * (box_x + blank_x), start_y + i * (box_y + blank_y), box_x, box_y, image))
                {
                    result[j] = i + "";
                }
            }
        }
        
        return result;
    }
    
    /**
    * 获取3个考号填涂区标准宽度和高度
    * @param params1 区域1
    * @param params2 区域2
    * @param params3 区域3
    * @return
    * @throws IOException
    * @see   [类、类#方法、类#成员]
    * @since [产品/模块版本]
    */
   @SuppressWarnings("unchecked")
   public Map<String,Object> getAreaWidthHeight(Map<String,Object> params) throws IOException{
       Map<String,Object> map = new HashMap<String,Object>();
       //读取3张图片流
       BufferedImage image1 = this.cropService.getCropImageBuffered((Map<String, Object>) params.get("map1"));
       BufferedImage image2 = this.cropService.getCropImageBuffered((Map<String, Object>) params.get("map2"));
       BufferedImage image3 = this.cropService.getCropImageBuffered((Map<String, Object>) params.get("map3"));
       //3张图片结果进行判断得出区域最终宽度和高度
       int singleWidth = 0;//单个填涂区宽度
       int singleHeight = 0;//单个填涂区高度
       if(image1!=null && image2!=null && image3!=null){
           Map<String,Object> map1 = this.getAreaResult(image1,0);
           Map<String,Object> map2 = this.getAreaResult(image2,0);
           Map<String,Object> map3 = this.getAreaResult(image3,0);
           int width1 = Integer.parseInt(map1.get("width")+"");
           int width2 = Integer.parseInt(map2.get("width")+"");
           int width3 = Integer.parseInt(map3.get("width")+"");
           int height1 = Integer.parseInt(map1.get("height")+"");
           int height2 = Integer.parseInt(map2.get("height")+"");
           int height3 = Integer.parseInt(map3.get("height")+"");
           //计算宽度
           if(width1==width2){
               singleWidth = width1;
           }else if(width2==width3){
               singleWidth = width2;
           }else if(width1==width3){
               singleWidth = width3;
           }else{
               singleWidth = (int)Math.round((width1+width2+width3)/3d);
           }
           //计算高度
           if(height1==height2){
               singleHeight = height1;
           }else if(height2==height3){
               singleHeight = height2;
           }else if(height1==height3){
               singleHeight = height3;
           }else{
               singleHeight = (int)Math.round((height1+height2+height3)/3d);
           }
       }
       
       map.put("singleWidth", singleWidth);
       map.put("singleHeight", singleHeight);
       return map;
   }
   
   /**
    * 获取单个填涂区标准宽度和高度
    * @param params 参数集
    * @return
    * @throws IOException
    * @see   [类、类#方法、类#成员]
    * @since [产品/模块版本]
    */
   public Map<String,Object> getSingleAreaWidthHeight(Map<String,Object> params) throws IOException{
       Map<String,Object> map = new HashMap<String,Object>();
       BufferedImage image = this.cropService.getCropImageBuffered(params);//读取图片流
       
       int singleWidth = 0;//单个填涂区宽度
       int singleHeight = 0;//单个填涂区高度
       int start_x = 0;
       int start_y = 0;
       if(image != null){
           Map<String,Object> map1 = this.getAreaResult(image,0);
           singleWidth = Integer.parseInt(map1.get("width")+"");
           singleHeight = Integer.parseInt(map1.get("height")+"");
           start_x = Integer.parseInt(map1.get("start_x")+"");
           start_y = Integer.parseInt(map1.get("start_y")+"");
       }
       
       map.put("start_x", start_x);
       map.put("start_y", start_y);
       map.put("singleWidth", singleWidth);
       map.put("singleHeight", singleHeight);
       return map;
   }
   
   /**
    * 获取考号区域实际宽度和高度
    * @param mbPath 模板路径
    * @param params 参数集
    * @return
    * @throws IOException
    * @see   [类、类#方法、类#成员]
    * @since [产品/模块版本]
    */
   public Map<String,Object> getKhAreaWidthHeight(Map<String,Object> params) throws IOException{
       Map<String,Object> map = new HashMap<String,Object>();
       BufferedImage image = this.cropService.getCropImageBuffered(params);//读取图片流
       if(image != null){
           Map<String,Object> map1 = this.getAreaResult(image,1);
           map.putAll(map1);
       }
       
       return map;
   }
    
    /**
     * 判断一个方格有没有被填涂
     * @param x X坐标
     * @param y Y坐标
     * @param box_x 列间距
     * @param box_y 行间距
     * @param image
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public boolean judge_box(int x, int y, int box_x, int box_y, BufferedImage image)
    {
        int i, j, total = 0, count = 0;
        Color color = null;
        // 循环判断所有点
        for (i = x; i < x + box_x; i++)
        {
            for (j = y; j < y + box_y; j++)
            {
                total++;
                
                color = new Color(image.getRGB(i, j));
                if (color.getBlue() <= 100)
                {
                    count++;
                }
            }
        }
        
        // 黑色的比例大于50%则认为该方格被填涂
        if (count / (total + 0d) >= 0.5)
        {
            return true;
        }
        return false;
    }
    
    /****************************客观题识别开始**********************************/
    /**
     * 识别客观题答案
     * @param image 图片流
     * @param params 参数
     * @param lx 截图类型
     * @return
     * @throws IOException
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String,String> recognitionObjectiveAnswer(BufferedImage image,CourseTemplateArea record,Map<String, Integer> params_) throws IOException
    {
        int start_x = record.getStartX();
        int start_y = record.getStartY();
        int area_width = record.getAreaWidth();
        int area_height = record.getAreaHeight();
        int rows = record.getRowCount();
        int cols = record.getColCount();
        int singleWidth = params_.get("areaWidth");
        int singleHeight = params_.get("areaHeight");
        int blank_x = (area_width - (cols * singleWidth)) / (cols - 1);// 列间隔宽度
        int blank_y = 0;
        if(rows > 1){
            blank_y = (area_height - (rows * singleHeight)) / (rows - 1);// 行间隔高度
        }
        int imgW = image.getWidth();
        int imgH = image.getHeight();
        
        Map<String, Integer> params = new HashMap<String, Integer>();
        params.put("rows", rows);
        params.put("cols", cols);
        params.put("box_x", singleWidth);
        params.put("box_y", singleHeight);
        params.put("ksth", record.getKsth());
        
        Map<String,String> resultMap = new HashMap<String,String>();
        boolean flag = false;
        // 将列间距blank_x 正负偏差4PX校对
        for (int i = 4; i > -5; i--)
        {
            int start_x1 = start_x + i;
            if (flag) break;
            
            int w = start_x1 + (cols * singleWidth) + (cols - 1) * blank_x;
            if (w > imgW) continue;
            if (start_x1 >= 0)
            {
                //start_y 对起始点高度进行正负5PX偏差校对，以增加识别准确率
                for (int j = 4; j > -5; j--)
                {
                    int start_y1 = start_y + j;
                    if (start_y1 >= 0)
                    {
                        // 将列间距blank_y 正负偏差3PX校对
                        for (int b = 2; b > -3; b--)
                        {
                            if (flag) break;
                            int blank_y1 = blank_y + b;
                            int h = start_y1 + (rows * singleHeight) + (rows - 1) * blank_y1;
                            if (h > imgH) continue;
                            params.put("start_x", start_x1);
                            params.put("start_y", start_y1);
                            params.put("blank_x", blank_x);
                            params.put("blank_y", blank_y1);
                            Map<String,String> resultMap_ = judgeKgt(params, image);//获取答案
                            if(resultMap_.get("flag").equals("0")){
                                //全部识别，退出循环
                                resultMap = resultMap_;
                                flag = true;
                                break;
                            }else{
                                //继续识别，查找识别最多的答案
                                if(resultMap.isEmpty()){
                                    resultMap = resultMap_;
                                }else{
                                    for(Map.Entry<String, String> entry : resultMap_.entrySet()){
                                        String key = entry.getKey();
                                        String val = entry.getValue();
                                        if(!StringUtils.isEmpty(val)){
                                            resultMap.put(key, val);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        resultMap.remove("flag");
        image = null;
        return resultMap;
    }
    
    /**
     * 判断所有的，入口参数分别是起始横坐标，起始纵坐标，行数，列数
     * @param map 参数
     * @param image 图片流
     * @return
     * @see   [类、类#方法、类#成员]
     * @since [产品/模块版本]
     */
    public Map<String,String> judgeKgt(Map<String, Integer> map, BufferedImage image)
    {
        int i, j;
        int cols = map.get("cols");
        int rows = map.get("rows");
        int start_x = map.get("start_x");
        int start_y = map.get("start_y");
        int box_x = map.get("box_x");
        int box_y = map.get("box_y");
        int blank_x = map.get("blank_x");
        int blank_y = map.get("blank_y");
        int ksth = map.get("ksth");//开始题号
        Map<String,String> resultMap = new HashMap<String,String>();//存放每行结果值
        int th = 0;
        String flag = "0";
        for (i = 0; i < rows; i++)
        {
            th = ksth + i;
            String str = "";
            for (j = 0; j < cols; j++)
            {
                if (judge_box(start_x + j * (box_x + blank_x), start_y + i * (box_y + blank_y), box_x, box_y, image))
                {
                    str += daxxMap.get(j)==null?"":daxxMap.get(j) + ",";//拼接多个选项值
                }
            }
            
            str = StringUtils.isEmpty(str)?"":str.substring(0, str.length()-1);
            if(StringUtils.isEmpty(str)){
                flag = "1";
            }
            resultMap.put(th+"", str);
        }
        
        resultMap.put("flag", flag);
        return resultMap;
    }
    /****************************客观题识别结束**********************************/
}
